<template>
  <VsFormItem
    v-if="isInited"
    :class="`form-item ${helptip ? 'form-item-helptip' : 'form-item-no-helptip'}`"
    :label="label"
    :label-width="labelWidth"
    :prop="option"
    :rules="getRules()"
  >
    <template #label>
      <span
        :class="`label ${helptip ? 'label-helptip' : ''}`"
      >
        <div class="label-content">
          <template v-if="tip">
            <el-tooltip
              :content="tip"
              placement="top"
            >
              <span>{{ label }}</span>
            </el-tooltip>
          </template>
          <template v-else>
            <span class="label-text">{{ label }}</span>
            <Helptip
              v-if="helptip"
              :tip-key="helpManualKey"
            >{{ helptip }}</Helptip>
          </template>
        </div>
      </span>
    </template>
    <div class="cont">
      <slot>
        <el-switch
          v-if="showSwitch"
          v-model="lastObj_[lastKey_].switch"
          @change="switchChange()"
        ></el-switch>
        <template v-if="!showSwitch || lastObj_[lastKey_].switch">
          <!-- input -->
          <ValueInputer
            v-if="type === 'input'"
            v-model:value="lastObj[lastKey]"
            :placeholder="placeholder"
          />

          <!-- number -->
          <Range
            v-else-if="type === 'number'"
            v-model:value="lastObj[lastKey]"
            type="input"
            :min="min_"
            :max="max_"
            :step="step"
            :stepStrictly="stepStrictly"
            :controls-position="controlsPosition"
            :precision="precision"
          />

          <!-- number_array -->
          <template v-else-if="type === 'number_array'">
            <Range
              v-for="(n, i) in lastObj[lastKey]"
              :key="i"
              v-model:value="lastObj[lastKey][i]"
              type="input"
              :step="step"
              :controls-position="controlsPosition"
              :precision="precision"
            />
          </template>

          <!-- color -->
          <ColorPicker
            v-else-if="type === 'color'"
            v-model:value="lastObj[lastKey]"
          />

          <!-- switch -->
          <el-switch
            v-else-if="type === 'switch'"
            v-model="lastObj[lastKey]"
          ></el-switch>

          <!-- switch_array -->
          <template v-else-if="type === 'switch_array'">
            <el-switch
              v-for="(n, i) in lastObj[lastKey]"
              :key="i"
              v-model="lastObj[lastKey][i]"
            ></el-switch>
          </template>

          <!-- select -->
          <el-select
            v-else-if="type === 'select'"
            v-model="lastObj[lastKey]"
            size="default"
            :popper-class="visualThemeClassName"
          >
            <el-option
              v-for="(n, i) in options"
              :key="i"
              :label="n.label"
              :value="n.value"
            ></el-option>
          </el-select>

          <!-- select_array -->
          <template v-else-if="type === 'select_array'">
            <el-select
              v-for="(item, index) in lastObj[lastKey]"
              :key="index"
              v-model="lastObj[lastKey][index]"
              size="default"
            >
              <el-option
                v-for="(n, i) in options"
                :key="i"
                :label="n.label"
                :value="n.value"
              ></el-option>
            </el-select>
          </template>

          <!-- checkbox_array -->
          <template v-else-if="type === 'checkbox_array'">
            <div>
              <el-checkbox
                v-for="(n, i) in lastObj[lastKey]"
                :key="i"
                v-model="lastObj[lastKey][i]"
              >
                {{ options[i].label }}
              </el-checkbox>
            </div>
          </template>

          <!-- radio -->
          <el-radio-group
            v-else-if="type === 'radio'"
            v-model="lastObj[lastKey]"
          >
            <el-radio
              v-for="(n, i) in options"
              :key="i"
              :label="n.value"
            >
              {{ n.label }}
              <Helptip v-if="n.value === 'continuous'">{{ $demoi18n('message.emptyAdd') }}</Helptip>
            </el-radio>
          </el-radio-group>

          <el-radio-group
            v-if="showUnit"
            v-model="lastObj_[lastKey_].unit"
            size="small"
            :class="`units units_${units.length}`"
          >
            <el-radio-button
              v-for="(n, i) in units"
              :key="i"
              :label="n.value"
            >{{ n.label }}</el-radio-button>
          </el-radio-group>
        </template>
      </slot>
    </div>
  </VsFormItem>
</template>
<script>
import ColorPicker from '@/components/common/color-picker/color-picker.vue';
import Helptip from '@/components/common/helptip/helptip.vue';
import Range from '@/components/common/range/range.vue';
import rulesConst from '@/rules/rules_constant.js';
import { rulesMap } from '@/rules/rules_map.js';
import { genRulesByKey } from '@/utils/rules';
import { objHas } from '@/utils/util';
import echartUtil from './echart-util.js';
import ValueInputer from '@/components/common/value-inputer/value-inputer.vue';

export default {
  components: {
    Range,
    ColorPicker,
    Helptip,
    ValueInputer,
  },
  props: {
    label: String,
    form: Object, // 等价于组件的 config.config.property
    option: String,
    type: String, // number, input, switch, select
    options: Array,

    // -------- 次要传参
    placeholder: String,
    labelWidth: {
      type: String,
      default: '30%',
    },
    min: Number,
    max: Number,
    step: {

      // 数值每次增量值
      type: Number,
      default: 1,
    },

    // 数值输入框是否只能输入 step 的倍数
    stepStrictly: {
      type: Boolean,
      default: false,
    },
    showSwitch: Boolean, // 是否可用开关，关闭则不可用，即使用echart默认配置
    showUnit: Boolean, // 是否显示单位，默认单位是px，可选percent|px
    units: {
      type: Array,
      default: () => [{ label: 'px', value: 'px' }, { label: '%', value: '%' }],
    },
    serieType: String,
    tip: String,
    helptip: String,
    switch: {
      type: [String, Boolean],
      default: '',
    },
    controlsPosition: {

      // 控制数字加减按钮位置
      type: String,
      default: '',
    },
    precision: {
      type: Number,
      default: 0,
    },
  },
  emits: ['change', 'switchChange'],
  data() {
    return {
      finalKey: '',
      lastObj: {},
      lastObj_: {},
      lastKey: '',
      lastKey_: '',
      isInited: false,
    };
  },
  computed: {
    min_() {
      let min;
      if (typeof this.min === 'number') {
        return this.min;
      }
      const key = this.option.replace(/\.\d+\./, '.[x].');
      const rule = rulesMap[this.option] || rulesMap[key];
      if (rule && objHas(rule, 'min')) {
        return rule.min;
      }
      return rulesConst.numberMin;
    },
    max_() {
      if (typeof this.max === 'number') {
        return this.max;
      }
      const key = this.option.replace(/\.\d+\./, '.[x].');
      const rule = rulesMap[this.option] || rulesMap[key];
      if (rule && objHas(rule, 'max')) {
        return rule.max;
      }
      return rulesConst.numberMax;
    },
    helpManualKey() {
      if (this.helptip) {
        const isKey = /^[a-zA-Z_]+\.[a-zA-Z_]+/.test(this.helptip); // 举例：tooltip_vars.basic_pie
        if (isKey) {
          return this.helptip;
        }
      }
      return '';
    },
  },
  watch: {
    showUnit() {
      this.initConf();
    },
    option(oldVal, newVal) {
      this.isInited = false;
      echartUtil.register(this.option, this.form, this, this.serieType);
      this.initLastObj();
      this.initLastKey();
      this.initConf();
      this.fixValue();
      this.isInited = true;

      this.initSwitch();
      this.initWatch();
    },
  },
  created() {
    this.isInited = false;
    echartUtil.register(this.option, this.form, this, this.serieType);
    this.initLastObj();
    this.initLastKey();
    this.initConf();
    this.fixValue();
    this.isInited = true;

    this.initSwitch();
    this.initWatch();
    this.initUnit();
  },
  methods: {

    // 返回倒数第二层对象，用于绑定v-model
    initLastObj() {
      const arr = this.option.split('.');
      const len = arr.length;
      let { form } = this;
      let form_ = this.form;
      for (let i = 0; i < len; i++) {
        const key = arr[i];
        if (i < len - 1) {
          form_ = form;
          form = form[key];
        }
      }
      this.lastObj = form;
      this.lastObj_ = form;
      if (Array.isArray(form)) {
        this.lastObj_ = form_;
      }
    },

    // 返回属性路径最后一个key
    initLastKey() {
      const arr = this.option.split('.');
      const lastKey = arr.pop();
      this.lastKey = lastKey;
      this.lastKey_ = `_${lastKey}`;

      if (Array.isArray(this.lastObj)) {
        const prevKey = arr.pop() || '';
        this.lastKey_ = `_${prevKey}_${lastKey}`;
      }
    },

    // 注册配置属性
    initConf() {
      if (this.showSwitch || this.showUnit) {
        const isArr = Array.isArray(this.lastObj);
        const _conf = echartUtil.getPropConfVal(this.option, '', this.form, this.serieType, isArr) || {};

        if (!objHas(_conf, 'switch') && this.showSwitch) {
          _conf['switch'] = false;
        }
        if (!objHas(_conf, 'unit')) {
          _conf['unit'] = this.units[0].value;
        }

        if (!this.lastObj_[this.lastKey_]) {
          this.lastObj_[this.lastKey_] = {};
        }

        Object.entries(_conf).map(([j]) => {
          this.lastObj_[this.lastKey_][j] = _conf[j];
        });
      }
    },

    // 修正数字类型
    fixValue() {
      if (this.lastObj[this.lastKey] === 'auto' && this.type === 'number') {
        this.lastObj[this.lastKey] = 0;
      }
    },

    // 主题风格切换 -> 颜色自动切换
    initWatch() {
      const _conf = echartUtil.getPropConfVal(this.option, '', this.form);
      if (_conf && _conf.dark && _conf.light) {
        this.$watch('form.componentStyle', (newVal, oldVal) => {
          this.lastObj[this.lastKey] = _conf[newVal];
        });
      }
      this.$watch(
        () => this.lastObj[this.lastKey],
        (newVal, oldVal) => {
          this.$emit('change', newVal);

          // 根属性修改，需要同步给form，因为lastObj跟form在非本地环境不是同一内存地址
          if (this.option.indexOf('.') === -1) {
            this.form[this.option] = newVal;
          }
        },
        { immediate: true },
      );
      this.$watch('switch', this.initSwitch);
    },

    getRules() {
      const rules = genRulesByKey(this.option);
      return rules;
    },

    initSwitch() {
      if (this.switch === true || this.switch === false) {
        this.lastObj_[this.lastKey_].switch = this.switch;
      }
    },

    initUnit() {
      if (this.units.length === 1) {
        this.lastObj_[this.lastKey_].unit = this.units[0].value;
      }
    },

    switchChange() {
      this.$emit('switchChange', this.lastObj_[this.lastKey_].switch);
    },
  },
};
</script>
<style lang="less" scoped>
.form-item {
  margin-bottom: 5px;
  :deep(.el-form-item__content) {
    display: flex;
    align-items: center;
    min-height: 40px;
  }
  .cont {
    display: flex;
    align-items: center;
    width: 100%;
    > * {
      margin-left: 10px;
      &:first-child {
        margin-left: 0;
      }
    }
    :deep(.units) {
      margin-left: 5px;
      flex-wrap: nowrap;
      display: flex;
      &.units_1{
        flex-basis: 26px;
      }
      .el-radio-button__inner {
        padding: 6px 6px;
      }
    }
  }
  .label {
    display: flex;
  }
  .label-helptip {
    width: 100%;
    justify-content: flex-end;
  }
  .label-content {
    display: flex;
    justify-content: flex-end;
    width: max-content;
    max-width: 100%;
  }
  .label-text {
    flex-grow: 1;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}
</style>
<style lang="less">
.form-item-helptip {
  .el-form-item__label {
    display: flex;
    justify-content: flex-end;
  }
}
.form-item-no-helptip {
  .el-form-item__label {
    display: flex;
    justify-content: flex-end;
  }
  .label {
    width: max-content;
    max-width: 100%;
  }
}
</style>
